package com.dq.service.goods.impl;

import com.alibaba.fastjson.JSONObject;
import com.dq.context.Constant;
import com.dq.domain.base.impl.BaseDaoImpl;
import com.dq.domain.goods.stock.StockChangeRecord;
import com.dq.domain.org.Org;
import com.dq.exception.customException.AdminException;
import com.dq.controller.in.goods.BossGoodsQuery;
import com.dq.controller.in.goods.stock.OrgGoodsAndStockQuery;
import com.dq.controller.in.base.BaseAdminQuery;
import com.dq.vo.ListDataVo;
import com.dq.vo.Vo;
import com.dq.domain.base.BaseDao;
import com.dq.domain.category.Category;
import com.dq.domain.goods.Goods;
import com.dq.domain.goods.Product;
import com.dq.domain.goods.centre.OrgGoodsCentre;
import com.dq.domain.sys.user.user.base.SysUser;
import com.dq.repository.BaseRepositories;
import com.dq.service.category.CategoryService;
import com.dq.service.goods.GoodsService;
import com.dq.service.org.OrgService;
import com.dq.utils.BeanNullUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Author luchangtong
 * @Date 2019/12/7 10:07
 */
@Service
public class GoodsServiceImpl extends BaseRepositories implements GoodsService {
    @Autowired
    private OrgService orgService;
    @Autowired
    private CategoryService categoryService;


    /**
     * 所有商品列表-不关联门店, 无库存
     */
    @Override
    public List<Goods> list(BossGoodsQuery bossGoodsQuery) {
        Map<String, Object> query = createQuery(bossGoodsQuery);
        return dao.find(dao.query2Hql(Goods.class, query), query);
    }
    @Override
    public Long count(BossGoodsQuery bossGoodsQuery) {
        Map<String, Object> query = createQuery(bossGoodsQuery);
        return dao.count(dao.count2Hql(Goods.class, query), query);
    }
    public Map<String, Object> createQuery(BossGoodsQuery bossGoodsQuery) {
        Map<String, Object> query = bossGoodsQuery.parseMap();
        if(bossGoodsQuery.getCategoryId() != null) {
            query.put("category_id", bossGoodsQuery.getCategoryId());
            query.remove("categoryId");
        }
        if (bossGoodsQuery.getBeginTime() != null) {
            query.put("createTime" + BaseDaoImpl.gteSqlStr, bossGoodsQuery.getBeginTime());
            query.remove("beginTime");
        }
        if (bossGoodsQuery.getEndTime() != null) {
            query.put("createTime" + BaseDaoImpl.lteSqlStr, bossGoodsQuery.getEndTime());
            query.remove("endTime");
        }
        if (bossGoodsQuery.getMinIntegral() != null) {
            query.put("integralNum" + BaseDaoImpl.gteSqlStr, bossGoodsQuery.getBeginTime());
            query.remove("minIntegral");
        }
        if (bossGoodsQuery.getMaxIntegral() != null) {
            query.put("integralNum" + BaseDaoImpl.lteSqlStr, bossGoodsQuery.getEndTime());
            query.remove("maxIntegral");
        }
        return query;
    }


    /**
     * 商品（goods）列表-关联门店, 携带门店信息/门店商品关联表的修改时间, 区别product
     */
    @Override
    public List<Goods> goodsByOrgList(OrgGoodsAndStockQuery orgGoodsStockQuery, Long orgId) throws AdminException {
        Map<String, Object> query = orgGoodsStockQuery.parseMap();

        query.put("org_id", orgId);
        query.remove("orgId");

        if(orgGoodsStockQuery.getGoodsId() != null) {
            query.put("goods_id", orgGoodsStockQuery.getGoodsId());
            query.remove("goodsId");
        }
        if(StringUtils.isNotBlank(orgGoodsStockQuery.getGoodsName())) {
            query.put("goods_goodsName"+ BaseDaoImpl.likeSqlStr, BaseAdminQuery.likeSql(orgGoodsStockQuery.getGoodsName()));
            query.remove("goodsName");
        }
        if(orgGoodsStockQuery.getGoodsStatus() != null) {
            query.put("goods_goodsStatus", orgGoodsStockQuery.getGoodsStatus());
            query.remove("goodsStatus");
        }
        if (orgGoodsStockQuery.getTimeBegin() != null) {
            query.put("last_modify_time" + BaseDaoImpl.gteSqlStr, orgGoodsStockQuery.getTimeBegin());
            query.remove("timeBegin");
        }
        if (orgGoodsStockQuery.getTimeEnd() != null) {
            query.put("last_modify_time" + BaseDaoImpl.lteSqlStr, orgGoodsStockQuery.getTimeEnd());
            query.remove("timeEnd");
        }
        if (orgGoodsStockQuery.getCategoryId() != null) {
            List<Long> idsInList = new ArrayList<>();
            idsInList.add(orgGoodsStockQuery.getCategoryId());
            List<Category> categoryList = categoryService.getParCategory(orgGoodsStockQuery.getCategoryId());
            for (Category category : categoryList) {
                idsInList.add(category.getId());
            }
            query.put("goods_category_id" + BaseDaoImpl.inSqlStr, idsInList);
        }

        query.put(BaseDaoImpl.HQL_GROUP, "u.goods.id, u.org.id");

        List<OrgGoodsCentre> orgGoodsCentres = dao.find(dao.query2Hql(OrgGoodsCentre.class, query), query);
        List<Goods> goodsListReturn = new ArrayList<>();
        for (OrgGoodsCentre orgGoodsCentre : orgGoodsCentres) {
            Goods goods = orgGoodsCentre.getGoods();
            goods.setOrgId(orgGoodsCentre.getOrg().getId());
            goods.setOrgName(orgGoodsCentre.getOrg().getSimpleName());
            goods.setChangeTime(orgGoodsCentre.getLastModifyTime());

            goodsListReturn.add(goods);
        }

        return goodsListReturn;
    }
    /**
     * 商品（goods）列表-关联门店, 携带库存/门店信息/门店商品关联表的修改时间, 区别product
     */
    @Override
    public List<Goods> goodsByOrgAndStockList(OrgGoodsAndStockQuery orgGoodsStockQuery, Long orgId, Boolean deleted) throws AdminException {
        StringBuilder sql = new StringBuilder();
        sql.append("SELECT SUM(og.count) goodsStock, og.last_modify_time changeTime, og.org_id orgId, d.simple_name orgName, a.* ");
        sql = getSqlApi(sql, orgId, false, orgGoodsStockQuery);

        Map<String, Object> query = new HashMap<>(16);
        if (orgGoodsStockQuery.getPage() != null && orgGoodsStockQuery.getSize() != null) {
            query.put("page", orgGoodsStockQuery.getPage());
            query.put("size", orgGoodsStockQuery.getSize());
        }

        List<Map> list = dao.findBySql2Map(sql.toString(), query);

        List<Goods> goodsListReturn = new ArrayList<>();
        List<Long> goodsIds = new ArrayList<>();
        for (Map m : list) {
//            Goods goods = GsonUtils.getDateGsonHump().fromJson(m.toString(), Goods.class);
//            goodsListReturn.add(goods);
            goodsIds.add(Long.parseLong(m.get("id").toString()));
        }

        List<Goods> goodsListByIds = goodsRepository.findByIdIn(goodsIds);
        for (Map m : list) {
            Goods goods1 = new Goods();
            for (Goods goods : goodsListByIds) {
                if (goods.getId().toString().equals(m.get("id").toString())) {
                    BeanUtils.copyProperties(goods, goods1, BeanNullUtil.getNullPropertyNames(goods));
                    if (m.get("goodsStock") != null) {
                        goods1.setGoodsStock(Long.parseLong(m.get("goodsStock").toString()));
                    }
                    goods1.setOrgId(Long.parseLong(m.get("orgId").toString()));
                    goods1.setOrgName(m.get("orgName").toString());
                    goods1.setChangeTime(Long.parseLong(m.get("changeTime").toString()));

                    goodsListReturn.add(goods1);
                    break;
                }
            }
        }

        return goodsListReturn;
    }

    @Override
    public Long goodsByOrgCount(OrgGoodsAndStockQuery orgGoodsStockQuery, Long orgId, Boolean deleted) throws AdminException {
        StringBuilder sql = new StringBuilder();
        sql.append("select count(nas.n) from ( SELECT count(a.id) n ");
        sql = getSqlApi(sql, orgId, deleted, orgGoodsStockQuery);
        sql.append(" ) nas");

        Map<String, Object> query = new HashMap<>(16);

        return dao.countBySql(sql.toString(), query);
    }

    private StringBuilder getSqlApi(StringBuilder sql, Long orgId, Boolean deleted, OrgGoodsAndStockQuery orgGoodsStockQuery) throws AdminException {
        sql.append(" FROM org_goods_centre og ");
        sql.append(" LEFT JOIN goods a ON a.id = og.goods_id ");
        sql.append(" LEFT JOIN category ca ON ca.id = a.category_id ");
        sql.append(" LEFT JOIN sys_section d ON d.id = og.org_id ");
        sql = getWhereSql(sql, orgId, deleted, orgGoodsStockQuery);

        sql.append(" GROUP BY a.id, og.org_id");
        sql.append(" order by og.last_modify_time desc");

        System.out.println(sql.toString());

        return sql;
    }
    private StringBuilder getWhereSql(StringBuilder sql, Long orgId, Boolean deleted, OrgGoodsAndStockQuery orgGoodsStockQuery) throws AdminException {
        if (deleted == null) {
            deleted = false;
        }
        sql.append(" where a.deleted = ").append(deleted);
        sql.append(" and og.deleted = ").append(false);

        if (orgId != null) {
            sql.append(" and og.org_id = ").append(orgId);
        } else {
           throw new AdminException("关联门店参数不能为空");
        }

        if(orgGoodsStockQuery.getGoodsId() != null) {
            sql.append(" and a.id = ").append(orgGoodsStockQuery.getGoodsId());
        }
        if (StringUtils.isNotBlank(orgGoodsStockQuery.getGoodsNo())) {
            sql.append(" and a.goods_no like '").append(BaseAdminQuery.likeSql(orgGoodsStockQuery.getGoodsNo())).append("'");
        }
        if (StringUtils.isNotBlank(orgGoodsStockQuery.getGoodsName())) {
            sql.append(" and a.goods_name like '").append(BaseAdminQuery.likeSql(orgGoodsStockQuery.getGoodsName())).append("'");
        }
        if (orgGoodsStockQuery.getGoodsStatus() != null) {
            sql.append(" and a.goods_status = ").append(orgGoodsStockQuery.getGoodsStatus().ordinal());
        }
        if (orgGoodsStockQuery.getTimeBegin() != null) {
            sql.append(" and og.last_modify_time >= ").append(orgGoodsStockQuery.getTimeBegin());
        }
        if (orgGoodsStockQuery.getTimeEnd() != null) {
            sql.append(" and og.last_modify_time <= ").append(orgGoodsStockQuery.getTimeEnd());
        }
        if (orgGoodsStockQuery.getCategoryId() != null) {
            StringBuilder inStr = new StringBuilder("" + orgGoodsStockQuery.getCategoryId());
            List<Category> categoryList = categoryService.getParCategory(orgGoodsStockQuery.getCategoryId());
            for (int i = 0; i < categoryList.size(); i++) {
                Category category = categoryList.get(i);
                if (i == 0) {
                    inStr.append(",");
                }
                if (i == categoryList.size() - 1) {
                    inStr.append(category.getId());
                } else {
                    inStr.append(category.getId()).append(",");
                }

            }
            sql.append(" and ca.id in (").append(inStr).append(")");
        }

        return sql;
    }

    /**
     * 商品（product）列表-关联门店, 携带库存/门店信息/门店商品关联表的修改时间, 区别 goods
     */
    @Override
    public List<Product> productAndStockList(OrgGoodsAndStockQuery orgGoodsStockQuery, Long orgId, Boolean deleted) throws AdminException {
        StringBuilder sql = new StringBuilder();
        sql.append("SELECT SUM(og.count) goodsStock, og.last_modify_time changeTime, og.org_id orgId, d.simple_name orgName, p.* ");
        sql = getSqlApiProduct(sql, orgId, deleted, orgGoodsStockQuery);

        // 设置动态参数
        Map<String, Object> query = new HashMap<>(16);
        if (orgGoodsStockQuery.getPage() != null && orgGoodsStockQuery.getSize() != null) {
            query.put("size", orgGoodsStockQuery.getSize());
            query.put("page", orgGoodsStockQuery.getPage());
        }

        List<Map> list = dao.findBySql2Map(sql.toString(), query);

        List<Product> listReturn = new ArrayList<>();
        List<Long> productIds = new ArrayList<>();
        for (Map m : list) {
            productIds.add(Long.parseLong(m.get("id").toString()));
        }
        List<Product> listByIds = productRepository.findByIdIn(productIds);
        for (Map m : list) {
            Product p = new Product();
            for (Product product : listByIds) {
                if (product.getId().toString().equals(m.get("id").toString())) {
                    BeanUtils.copyProperties(product, p, BeanNullUtil.getNullPropertyNames(product));
                    if (m.get("goodsStock") != null) {
                        p.setGoodsStock(Long.parseLong(m.get("goodsStock").toString()));
                    }
                    p.setChangeTime(Long.parseLong(m.get("changeTime").toString()));
                    p.getGoods().setOrgId(Long.parseLong(m.get("orgId").toString()));
                    p.getGoods().setOrgName(m.get("orgName").toString());

                    listReturn.add(p);
                    break;
                }
            }
        }

        return listReturn;
    }

    @Override
    public Long productAndStockCount(OrgGoodsAndStockQuery orgGoodsStockQuery, Long orgId, Boolean deleted) throws AdminException {
        StringBuilder sql = new StringBuilder();
        sql.append("select count(nas.n) from ( SELECT count(a.id) n ");
        sql = getSqlApiProduct(sql, orgId, deleted, orgGoodsStockQuery);
        sql.append(" ) nas");

        Map<String, Object> query = new HashMap<>(16);

        return dao.countBySql(sql.toString(), query);
    }

    private StringBuilder getSqlApiProduct(StringBuilder sql, Long orgId, Boolean deleted, OrgGoodsAndStockQuery orgGoodsStockQuery) throws AdminException {
        if (deleted == null) {
            deleted = false;
        }
        sql.append(" FROM org_goods_centre og ");
        sql.append(" LEFT JOIN goods a ON a.id = og.goods_id ");
        sql.append(" LEFT JOIN category ca ON ca.id = a.category_id ");
        sql.append(" LEFT JOIN product p ON p.id = og.product_id ");
        sql.append(" LEFT JOIN sys_section d ON d.id = og.org_id ");
        sql = getWhereSql(sql, orgId, deleted, orgGoodsStockQuery);

        sql.append(" GROUP BY p.id, og.org_id");
        sql.append(" order by og.last_modify_time desc");

        System.out.println(sql.toString());

        return sql;
    }

    /**
     * 获取 单个 goods 库存
     */
    @Override
    public Long goodsStock(Long goodsId, Long orgId) throws AdminException {
        if (goodsId == null || orgId == null) {
            throw new AdminException("参数为空");
        }
        StringBuilder sql = new StringBuilder();
        sql.append("SELECT SUM(og.count) goodsStock ");
        sql.append(" FROM org_goods_centre og ");
        sql.append(" LEFT JOIN goods a ON a.id = og.goods_id ");

        sql.append(" where og.deleted = ").append(false);
        sql.append(" and og.goods_id = ").append(goodsId);
        sql.append(" and og.org_id = ").append(orgId);

        sql.append(" GROUP BY og.goods_id, og.org_id");

        List<Map> list = dao.findBySql2Map(sql.toString(), new HashMap<>(16));
        long stock = 0L;
        if (list != null && list.size() > 0) {
            if (list.size() > 1) {
                throw new AdminException("数据异常");
            }
            Map map = list.get(0);
            stock = Long.parseLong(map.get("goodsStock").toString());
        }

        return stock;
    }

    /**
     * 获取 单个 product 库存
     */
    @Override
    public Long productStock(Long productId, Long orgId) throws AdminException {
        if (productId == null || orgId == null) {
            throw new AdminException("参数为空");
        }
        StringBuilder sql = new StringBuilder();
        sql.append("SELECT SUM(og.count) goodsStock ");
        sql.append(" FROM org_goods_centre og ");
        sql.append(" LEFT JOIN product p ON p.id = og.product_id ");

        sql.append(" where og.deleted = ").append(false);
        sql.append(" and og.product_id = ").append(productId);
        sql.append(" and og.org_id = ").append(orgId);

        sql.append(" GROUP BY og.product_id, og.org_id");

        List<Map> list = dao.findBySql2Map(sql.toString(), new HashMap<>(16));
        long stock = 0L;
        if (list != null && list.size() > 0) {
            if (list.size() > 1) {
                throw new AdminException("数据异常");
            }
            Map map = list.get(0);
            stock = Long.parseLong(map.get("goodsStock").toString());
        }

        return stock;
    }


    /**
     * 商品删除, 删除门店商品关联对象, 生成库存变动记录
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteGoods(Long goodsId) throws AdminException {
        SysUser loginUser = sysUserService.getUserInSection();
        Goods goods = dao.get(Goods.class, goodsId);
        if (goods == null) {
            throw new AdminException("删除商品不存在");
        }

        List<Product> products = productRepository.findByGoodsAndDeletedFalse(goods);
        for (Product product : products) {
            product.setDeleted(true);
            product.setUpdateUser(loginUser);
        }

        goods.setDeleted(true);
        goods.setUpdateUser(loginUser);

        // 删除商品门店关联对象, 生生库存变动记录
        List<OrgGoodsCentre> orgGoodsCentres = orgGoodsCentreRepository.findByGoodsAndDeletedFalse(goods);
        orgGoodsCentreService.delList(orgGoodsCentres);

        productRepository.saveAll(products);
        goodsRepository.save(goods);
    }

    /**
     * 对象初始化
     */
    @Override
    public Goods initObject(Goods goods) throws AdminException {
        SysUser user = sysUserService.getUser();
        goods.setCreateUser(user);
        goods.setUpdateUser(user);

        return goods;
    }
}
